/*******************************************************************************
Paper  	: A connectionist system for Online feature Selection.
Author  : N.R. Pal

*******************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
/******************************************************************************/
/******************************************************************************/
char	*filename;
int	inpNode,hidNode,outNode,index1,counter=1;
long	iter=0,cntTrnData=0,epoc=0;
int	Misclsf = 0,fp =0, fn = 0,ch,misc=0,amaxInd,dmaxInd;
double	**wih,**who,**pwih,**cwih,**pwho,**cwho,**trnData,d,**image_info;
double	*attenFun,*beta,*pbeta,**aoutput,*delta,*delta1,*delta_inp,*outdelta,*delbeta,**err,**doutTrn;
double 	prevsse=0,sse=0,**aoutput1,*netValHid,*hidActiv,*netValOup,*outActiv,n=0.9,mu=0.4;
int 	modify=0;
long 	*fpos,*fneg;
/******************************************************************************/
/******************************************************************************/
void	training();
void 	initialize();
void 	memory_free();
void 	Free(double ** , int );
void 	weight_initialization();
double	sigmoid(double );
double 	**memory2double(int ,int ,char * );
double *iv;

time_t t;
FILE *st,*image_info_fp;
/******************************************************************************/
int main()
{
	st=fopen("status_feature_selection.txt","w");
	fclose(st);
	
	
	initialize();
	
	training();	
	
	memory_free();
	
	return(0);	
}
/******************************************************************************/

void 	initialize()
{
	long i,j;
	FILE *fp;
	/*printf("\n Enter the no of input nodes...");
	scanf("%d",&inpNode);
	
	printf("\n Enter the no of hidden nodes...");
	scanf("%d",&hidNode);
	
	printf("\n Enter the no of output nodes...");
	scanf("%d",&outNode);
	
	printf("\n Enter the no of iterations...");
	scanf("%d",&iter);
	
	printf("\n Enter the name of the input file...");
	scanf("%s",filename);*/
	inpNode=95;
	hidNode=60;
	outNode=2;
	
	iter=50000;
	filename="full_train_norm_mix_4_100.txt";
	
	fp = fopen(filename,"r");
	while(!feof(fp))
	{
		if((ch=getc(fp))=='\n')
			cntTrnData++;
			
	}
	fclose(fp);
	
	fpos=(long*)calloc(cntTrnData,sizeof(long));
	fneg=(long*)calloc(cntTrnData,sizeof(long));
	
	trnData = memory2double(cntTrnData,inpNode+outNode,"trnData");
	image_info=(double**)malloc(cntTrnData*sizeof(double*));	
	for(long image_info_index=0;image_info_index<cntTrnData;image_info_index++)
	{
		image_info[image_info_index]=(double*)malloc(3*sizeof(double));
	}
	/*********READING THE TRAINING FILE**************/
	
	fp = fopen(filename,"r");
	for(i = 0 ; i < cntTrnData ; i++)
	{	
		for(int k1=0;k1<3;k1++)
		{
			fscanf(fp,"%lf",&image_info[i][k1]);
		}
		
		for(j = 0 ; j <(inpNode+outNode) ; j++)
		{
			fscanf(fp,"%lf",&trnData[i][j]);
			/*printf("%lf ",trnData[i][j]);*/
		}
		printf("\n");
	}
	fclose(fp);
	
	/***** INTIALIZING THE WEGHT OF THE NN ***************/			
	weight_initialization();
	
	return;	
}
/******************************************************************************/


void weight_initialization()
{
	long 	seed;
	long 	i,j;
	
	
	wih = memory2double(hidNode,inpNode,"wih");	
	cwih = memory2double(hidNode,inpNode,"cwih");
	pwih = memory2double(hidNode,inpNode,"pwih");
	
	who = memory2double(outNode,hidNode,"who");
	cwho = memory2double(outNode,hidNode,"cwho");
	pwho = memory2double(outNode,hidNode,"pwho");
	
	/******  MEMORY ALLOCATION 2 STORE ATTENUATION VALUES ******/
	
	attenFun = (double*)calloc(inpNode,sizeof(double));
	beta = (double*)calloc(inpNode,sizeof(double));
	pbeta = (double*)calloc(inpNode,sizeof(double));	
	delta1 = (double*)calloc(hidNode,sizeof(double));
	delta = (double*)calloc(hidNode,sizeof(double));
	delta_inp =(double*)calloc(inpNode,sizeof(double));
	outdelta=(double*)calloc(outNode,sizeof(double));
	delbeta	=(double*)calloc(inpNode,sizeof(double));
	
	srand((unsigned)time(&t));
	
	for(i = 0 ;i <hidNode ; i++)
	{
		for(j = 0 ; j <inpNode ; j++)
		{
			
			d=(double)rand()/32767;
			wih[i][j]=d-0.5;
			pwih[i][j] = wih[i][j];	
			
			printf("%9.4lf ",wih[i][j]);
		}
		printf("\n");
	}
	
	srand((unsigned)time(&t));
	
	for(i = 0 ; i < outNode ; i++)
	{
		for(j = 0 ; j < hidNode ; j++)
		{
			
			
			d=(double)rand()/32767;
			who[i][j]=d-0.5;
			
			pwho[i][j] = who[i][j];
			
			printf("%9.4lf ",who[i][j]);
		}
		printf("\n");
	}
	
	getchar();
	
	for( i = 0 ; i < inpNode ; i++)
	{
		beta[i] = -5.0;
		pbeta[i] = -5.0;
	}
	
	for(i = 0 ; i < inpNode ; i++)
	{
		attenFun[i] = sigmoid(beta[i]);		
	}
	/*for(i = 0 ; i < inpNode ; i++)
	{
		printf("attenFun[%d] =%lf\n",i,attenFun[i]);		
	}*/
	return;	
		
}
/******************************************************************************/


double **memory2double(int a,int b,char *s)
{
	double **temp;
	int i;
	
	temp = (double**)calloc(a,sizeof(double*));
	
	if(temp == NULL)
	{
		printf("\n Error %s\n",s);
		exit(0);
	}
	for(i = 0; i < a; i++)
	{
		temp[i] = (double*)calloc(b,sizeof(double));
		if(temp[i] == NULL)
		{
			printf("\n Error %s[%d]\n",s,i);
			exit(0);
		}
	}
	
	return(temp);
}


/******************************************************************************/
double sigmoid(double x)
{
	double sig;
	double d;
	d=exp(-x);
	d=d+1;
	sig = (double)(1/d);
	return(sig);
}
/******************************************************************************/
void training()
{
	
	FILE	*fp1,*fp2,*fp3;
	long 	i,j,k;
	char	name1[50],name2[50],name3[50],*index;
	
	
	/********DYNAMIC MEMORY ALLOCATION FOR THE DESIRED OUTPUT ARRAY*******/
	doutTrn = memory2double(cntTrnData,outNode,"doutTrn");
	aoutput = memory2double(cntTrnData,outNode,"aoutput");
	aoutput1= memory2double(cntTrnData,outNode,"aoutput1");
	err	= memory2double(cntTrnData,outNode,"err");
	
	/********DYNAMIC MEMORY ALLOCATION FOR THE ACTIVATION VALUES**********/
	
	netValHid = (double*)calloc(hidNode,sizeof(double));
	hidActiv = (double*)calloc(hidNode,sizeof(double));	
	netValOup = (double*)calloc(outNode,sizeof(double));
	outActiv=(double*)calloc(outNode,sizeof(double));
	
	for(i = 0 ; i < cntTrnData ; i++)
	{
		for(j=0 ; j<outNode; j++)
		{
			doutTrn[i][j] = trnData[i][inpNode+j];			
		}	
	}
	iv=(double*)malloc(inpNode*sizeof(double));	
	epoc = 0;
   while(epoc<iter)
   {	
	

	for(long k=0;k<cntTrnData;k++)
	{
		for(i=0;i<inpNode;i++)
			iv[i]=trnData[k][i]*attenFun[i];
	
	
	/****************************************HIDDEN ACTIVATION CALC*****************************/
		for(i=0;i<hidNode;i++)
		{	
			netValHid[i]=0;
			for(j=0;j<inpNode;j++)
				netValHid[i]+=iv[j]*wih[i][j];
			hidActiv[i]=sigmoid(netValHid[i]);
		}
	/*********************************************************************************************/
	
	
	/************************************OUTPUT CALC*********************************************************/
	
		for(i=0;i<outNode;i++)
		{	
			netValOup[i]=0;
			for(j=0;j<hidNode;j++)
				netValOup[i]+=hidActiv[j]*who[i][j];
			outActiv[i]=sigmoid(netValOup[i]);
		}
		
	/*********************************************************************************************/
	
	
	/*****************************************OUTPUT ERROR CALC****************************************************/
	
		for(i=0;i<outNode;i++)
			{
				err[k][i]=0;
				err[k][i]=(doutTrn[k][i]-outActiv[i]);
			}
	
		
	
		
	
	/*********************************************************************************************/
	
	
	/****************************************OUTPUT LAYER DELTA*****************************************************/
		
		for(i=0;i<outNode;i++)
			outdelta[i]=err[k][i]*outActiv[i]*(1-outActiv[i]);
		
	
	/*********************************************************************************************/
	
	
	/******************************HIDDEN TO OUTPUT DEL WEIGHT***************************************************************/
	
		for(i=0;i<outNode;i++)
			for(j=0;j<hidNode;j++)
		  		 cwho[i][j]=n*outdelta[i]*hidActiv[j];
	
	/*********************************************************************************************/
	
	
	/****************************HIDDEN LAYER DELTA CALC*****************************************************************/
	
	
		for(i=0;i<hidNode;i++)
		{
			delta[i]=0.0;
		}
		
		
		for(i=0;i<hidNode;i++)
		{
			for(j=0;j<outNode;j++)
			{
				delta[i]+=outdelta[j]*who[j][i];
			}
			delta[i]=delta[i]*hidActiv[i]*(1-hidActiv[i]);
			
		}
	
	/**********************************************************************************************************/
	
	
	/************************************INPUT TO HIDDEN DEL WEIGHT**********************************************************************/
	
		for(i=0;i<hidNode;i++)
		{
			for(j=0;j<inpNode;j++)
			{
				cwih[i][j]=n*delta[i]*iv[j];
			}
		}
	
	
	/**********************************************************************************************************/
	
	
	
	
	/*********************************ACTUAL INPUT TO ATTENUATE DELTA*************************************************************************/
	
		
		
		for(j=0;j<inpNode;j++)
			{
				delta_inp[j]=0.0;
			}
		
		
		for(i=0;i<hidNode;i++)
		{
			for(j=0;j<inpNode;j++)
			{
				delta_inp[j]+=wih[i][j]*delta[i];
			}
			
		}
		
		for(j=0;j<inpNode;j++)
		{	
			delbeta[j]=mu*trnData[k][j]*sigmoid(beta[j])*(1-sigmoid(beta[j]))*delta_inp[j];
		}
	
	
	/**********************************************************************************************************/
	
	
	/*******************************************UPDATION OF WHO***************************************************************/
	

		for(i=0;i<outNode;i++)
		{
			for(j=0;j<hidNode;j++)
			{
				who[i][j]=who[i][j]+cwho[i][j];
			}
		}	
	/**********************************************************************************************************/
	
	
	/********************************************UPDATION OF WIH**************************************************************/
	
		for(i=0;i<hidNode;i++)
		{
			for(j=0;j<inpNode;j++)
			{
				wih[i][j]=wih[i][j]+cwih[i][j];
			}
		}
	
	
	/**********************************************************************************************************/
	
	
	
	/****************************************UPDATION OF ATTENUATORS******************************************************************/
	
		for(i=0;i<inpNode;i++)
		{
			beta[i]=beta[i]+delbeta[i];
			attenFun[i]=sigmoid(beta[i]);
		}
		
	
	/**********************************************************************************************************/
	}
	
	
	/******************************************SECTION COPIED****************************************************/
	
	Misclsf = 0;fp = 0; fn = 0;
		sse = 0;								
		
		for(k = 0; k < cntTrnData; k++)
		{
			for(i = 0 ; i < hidNode ; i++)
			{
				netValHid[i] = hidActiv[i] = 0;
				for(j = 0 ; j < inpNode ; j++)
				{
					netValHid[i]+= (wih[i][j]*(trnData[k][j] * attenFun[j]));
				}
			}
			
			for(i = 0 ; i < hidNode ; i++)
			{
				hidActiv[i] = sigmoid(netValHid[i]);
			}
			
							
			for(i = 0 ; i < outNode ; i++)
			{
				netValOup[i] = aoutput1[k][i] = 0;
				for(j = 0 ; j < hidNode ; j++)
				{
					netValOup[i]+= (who[i][j] * hidActiv[j]);
				}
			}
			for(i = 0;i<outNode ;i++)
			{				
				aoutput1[k][i] = sigmoid(netValOup[i]);
				/*printf("aoutput%lf",aoutput1[k][i]);*/
				
				
			}
			for(i=0 ; i<outNode ;i++)
			{	
				err[k][i] = doutTrn[k][i] - aoutput1[k][i];
				sse+= err[k][i] * err[k][i];
			}	
			
			
			if(epoc == 0 )
			{
				for(i=0 ; i<outNode ;i++)
				{
					prevsse+= err[k][i] * err[k][i];
				}									
			}
				
			amaxInd = 0;
			dmaxInd = 0;
			for(i=0 ; i<(outNode-1) ;i++)
			{
				if(aoutput1[k][i]<aoutput1[k][i+1])
				{
					amaxInd = i+1;
				}
				
				if(doutTrn[k][i]<doutTrn[k][i+1])
				{
					dmaxInd = i+1;
				}
				
			}	
			
			if(amaxInd!=dmaxInd)
			{
				Misclsf++;
				if(amaxInd < dmaxInd)
				{
					fp++;
					fpos[k]=fpos[k]+1;
				}
				else{
					fn++;
					fneg[k]=fneg[k]+1;
					
				   }
			}	
					
		}
		
		if(sse > prevsse)
		{
			
			
			for(i = 0 ; i < hidNode ; i++)
			{
				for(j = 0 ;j < inpNode ; j++)
				{
					wih[i][j] = pwih[i][j];
					
				}
			}
			
			for(i = 0 ;i < outNode ; i++)
			{
				for(j = 0 ; j < hidNode ; j++)
				{
					who[i][j] = pwho[i][j];
				}
			}
			for(i=0 ; i<inpNode ; i++)
			{
				beta[i] = pbeta[i];
			}
			for(i=0 ; i <inpNode ; i++)
			{
				attenFun[i] = sigmoid(beta[i]);
			}			
			
						
			n=0.99*n;
						
			prevsse = prevsse;
			sse=prevsse;
			
		}
		else 
		{
			prevsse = sse;
			for(i = 0 ; i < outNode ; i++)
			{
				for(j = 0 ;j < hidNode ; j++)
				{
					pwho[i][j] = who[i][j];
				}
			}
			for(i = 0 ;i < hidNode ; i++)
			{
				for(j = 0 ; j < inpNode ; j++)
				{
					pwih[i][j] = wih[i][j];
				}
			}
			for(i=0 ; i<inpNode ; i++)
			{
				pbeta[i] = beta[i];
			}	
		}	
		
		
		/*printf("\n Epoch = %d ",epoc);*/
		if((epoc % 50) == 0)
		{
			printf("\nEpoch= %d",epoc);
			printf("\n Sum square error = %lf",sse);
			printf("\n Misclassification = %d (%d + %d)",Misclsf,fp,fn);
			printf("\n Learning parameter = %lf",n);
			printf("\n learning parameter for attenfun = %lf\n",mu);
			for(i = 0 ; i < inpNode ; i++)
			{
				printf(" af[%d] = %lf\n",i,attenFun[i]);
		
			}
			
			st=fopen("status_feature_selection.txt","a");
			fprintf(st,"%d  %d ( %d + %d ) %lf %lf\n", epoc,Misclsf,fp,fn,sse,n);
			fclose(st);
		}
		
			
		if(epoc %50 == 0)
		{
			char *str;
			char *wrong_file,*wrong_file_neg;
			int m=1,index_str=0;
			index1=epoc/50;
			str=(char*)malloc(sizeof(char));
			while(index1!=0)
			{
				
				m=index1%10;
				index1=index1/10;
				
				str[index_str]=m+48;
				index_str++;
				str=(char*)realloc(str,(index_str+1)*sizeof(char));
				
			}
			str[index_str]='\0';
			
			int len,forward=0,backward;
			len=strlen(str);
						
			index=(char*)malloc((len+1)*sizeof(char));
			for(backward=len-1;backward>=0;backward--)
			{
				index[forward]=str[backward];
				++forward;
			}
			index[forward]='\0';			
			
			strcpy(name1,"atn");
			strcat(name1,index);
			strcat(name1,".txt");
			
			strcpy(name2,"wih");
			strcat(name2,index);
			strcat(name2,".txt");
			
			strcpy(name3,"who");
			strcat(name3,index);
			strcat(name3,".txt");
			
			
			fp1 = fopen(name1,"w");
			fp2 = fopen(name2,"w");
			fp3 = fopen(name3,"w");
			
			strcpy(wrong_file,"wrongpos");
			strcat(wrong_file,index);
			strcat(wrong_file,".txt");
			
			image_info_fp=fopen(wrong_file,"w");
			free(wrong_file);
			
			strcpy(wrong_file_neg,"wrongneg");
			strcat(wrong_file_neg,index);
			strcat(wrong_file_neg,".txt");
			
			free(str);
			free(index);
			
			for(i=0;i<cntTrnData;i++)
			{
				if(fpos[i]>0)
				{
					fprintf(image_info_fp,"%015.3lf  %015.3lf  %015.3lf  %015.3lf\n",image_info[i][0],image_info[i][1],image_info[i][2],(double)fpos[i]);
					fpos[i]=0;
				}
				
			}
			
			fclose(image_info_fp);
			
			image_info_fp=fopen(wrong_file_neg,"w");
			
			
			for(i=0;i<cntTrnData;i++)
			{
				if(fneg[i]>0)
				{
					fprintf(image_info_fp,"%015.3lf  %015.3lf  %015.3lf  %015.3lf\n",image_info[i][0],image_info[i][1],image_info[i][2],(double)fneg[i]);
					fneg[i]=0;
				}
				
			}
			fclose(image_info_fp);
			
			
			for(i=0 ; i<inpNode ; i++)
			{
				fprintf(fp1,"af[%d] = %lf \n",i,attenFun[i]);
			}
			fprintf(fp1,"\n");
			
			for(i=0 ; i<hidNode ; i++)
			{
				for(j=0 ; j<inpNode ; j++)
				{
					fprintf(fp2,"%lf \t",wih[i][j]);
				}
				fprintf(fp2,"\n");
			}
			
			for(i=0 ; i<outNode ; i++)
			{
				for(j=0 ; j<hidNode ; j++)
				{
					fprintf(fp3,"%lf \t",who[i][j]);
				}
				fprintf(fp3,"\n");
			}			
			
			fclose(fp1);
			fclose(fp2);
			fclose(fp3);
		}
	
	/**************************************************************************************************************/
	
	
	epoc++;	
  }

	return;	
}	

/******************************************************************************/
void memory_free()
{
	Free(wih,hidNode);
	Free(cwih,hidNode);
	Free(pwih,hidNode);
	Free(who,outNode);
	Free(cwho,outNode);
	Free(pwho,outNode);
	free(attenFun);
	free(beta);
	free(pbeta);
	free(delta1);
	free(delta);
	free(delta_inp);
	Free(trnData,cntTrnData);
	Free(doutTrn,cntTrnData);
	Free(aoutput,cntTrnData);
	Free(aoutput1,cntTrnData);
	Free(err,cntTrnData);
	free(netValHid);
	free(hidActiv);
	free(netValOup);
	
	return;
	
}	


/******************************************************************************/
void Free(double **node, int a)
{
	int i;
	
	for(i=0;i<a;i++)
		free(node[i]);
	
	free(node);
	return;
}
/******************************************************************************/
/******************************************************************************/
